/*********************************************************************
*
* Software License Agreement (BSD License)
*
*  Copyright (c) 2010, Heriot-Watt University, UK.
*  All rights reserved.
*
*  Redistribution and use in source and binary forms, with or without
*  modification, are permitted provided that the following conditions
*  are met:
*
*   * Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*   * Redistributions in binary form must reproduce the above
*     copyright notice, this list of conditions and the following
*     disclaimer in the documentation and/or other materials provided
*     with the distribution.
*   * Neither the name of the Heriot-Watt University nor the names of
*     its contributors may be used to endorse or promote products
*     derived from this software without specific prior written
*     permission.
*
*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
*  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
*  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
*  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
*  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
*  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
*  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
*  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
*  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
*  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
*  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
*  POSSIBILITY OF SUCH DAMAGE.
*
*  Author: Joel Cartwright
*
*********************************************************************/

#ifndef MATCHMAKER_SERVICE_ADVERTISER_H_
#define MATCHMAKER_SERVICE_ADVERTISER_H_

#include <list>

#include <boost/shared_ptr.hpp>

#include <matchmaker/service_details.h>

#include <matchmaker_msgs/Advert.h>

namespace matchmaker
{

// Forward declaration.
class ServiceAdvertiser;

/**
 * @brief Class representing an ongoing service advertisement using the Client
 *
 * Most users will only need to call the setStatus method.
 *
 * Non-empty instances of this class can only be created by the Client.
 */
class ServiceAdvertiser
{
public:
  /**
   * @brief Constructor for an empty instance
   */
  ServiceAdvertiser();

  /**
   * @brief Copy constructor
   * @param rhs object to copy
   */
  ServiceAdvertiser(const ServiceAdvertiser& rhs);

  /**
   * @brief Destructor
   *
   * Calls shutdown if the object is valid.
   */
  ~ServiceAdvertiser();

  /**
   * @brief Stop advertising the service
   *
   * This method is automatically called by the destructor. Note that if
   * there are multiple (user) copies of a particular ServiceAdvertiser,
   * only when they are all shutdown or destroyed will the matchmaker Client
   * library stop advertising the service.
   */
  void shutdown();

  /**
   * @brief Get the name of the service being advertised
   * @return service name
   */
  std::string getName() const;

  /**
   * @brief Set the status of the service being advertised
   *
   * This may be called as often as required, as only status changes are
   * communicated to the matchmaker Server. Thus no-change calls to
   * setStatus are a very lightweight local operation.
   *
   * @param status new service status
   */
  void setStatus(const ServiceStatus& status);

  /**
   * @brief Set the status of the service being advertised
   *
   * This is a convenience wrapper to be used in place of
   * setStatus(ServiceStatus(value, extraStatus)).
   * It may be called as often as required, as only status changes are
   * communicated to the matchmaker Server. Thus no-change calls to
   * setStatus are a very lightweight local operation.
   *
   * @param value
   * @param extraStatus
   */
  void setStatus(ServiceStatus::Enum value, const std::string extraStatus);

  /**
   * @brief Get the last status that was set
   * @return last status
   */
  ServiceStatus getStatus() const;

  /**
   * @brief Get the time the status was last set
   * @return last status set time, or zero time if never set
   */
  ros::Time getStatusTime() const;

  /**
   * @brief Test if this ServiceAdvertiser copy is valid, and not shutdown
   *
   * This overloaded operator allows instances of the advertiser to be
   * tested for validity like so:
\verbatim
if (monitor) { ... }
\endverbatim
   * @return (void*)1 if valid, (void*)0 if not
   */
  operator void*() const { return (impl_) ? (void*)1 : (void*)0; }

// -----------------------------------------
// Users should ignore code below this line.
// -----------------------------------------

  bool operator<(const ServiceAdvertiser& rhs) const
  {
    return impl_ < rhs.impl_;
  }

  bool operator==(const ServiceAdvertiser& rhs) const
  {
    return impl_ == rhs.impl_;
  }

  bool operator!=(const ServiceAdvertiser& rhs) const
  {
    return impl_ != rhs.impl_;
  }

private:
  ServiceAdvertiser(const std::string & soaName, const std::string & topic,
      boost::function<void (ServiceAdvertiser *)> advertiseCallback);

  matchmaker_msgs::Advert* getAdvertMsg();

  ros::Time getCreationTime() const;

  long int getNumCopies();

  /**
   * @brief Internal details of the ServiceAdvertiser, not for external use
   */
  class Impl
  {
  public:
    Impl();
    ~Impl();

    ros::Time creationTime_;
    boost::function<void (ServiceAdvertiser *)> advertiseCallback_;
    matchmaker_msgs::Advert advertMsg_;
  };

  typedef boost::shared_ptr<Impl> ImplPtr;
  typedef boost::weak_ptr<Impl> ImplWPtr;

  ImplPtr impl_;

  friend class Client;
};

typedef std::list<ServiceAdvertiser> L_ServiceAdvertiser;

}

#endif /* MATCHMAKER_SERVICE_ADVERTISER_H_ */
